/*
 *
 * Core function calls taken from main.c from the lwbt-0.1/ports/linux/main.c
 *
 */

#include <stdio.h>
#include <errno.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <signal.h>
#include <termios.h>

#include <math.h>

#include <sys/types.h>

#include <sys/time.h>
#include <unistd.h>

#include <pthread.h>


#define byte unsigned char

/*-----------------------------------------------------------------------------------*/
/* 
 * Global data used by library
 *
 */
struct phybusif_cb *cb;

byte lib_is_setup=0;
byte lib_is_init=0;

byte lib_is_scanning=0;
byte lib_is_connecting=0;

byte lib_interactive_pin=0;

byte hci_scan_num_devices = 0;


byte local_mac_addr[6];
byte local_name[250];

byte pin_code[10];

#define LIB_IDLE         0

#define LIB_SCANNING     10
#define LIB_MONITORING   20
#define LIB_CONNECTING   30

#define LIB_STOP         100
#define LIB_SHUTDOWN     200


#define RFCOMM_IDLE         0
#define RFCOMM_IN_PROGRESS  1
#define RFCOMM_NO_DEV       2
#define RFCOMM_NO_SDP_REC   3
#define RFCOMM_NO_CHAN      4
#define RFCOMM_CONN_REF     5
#define RFCOMM_CONNECTED    6

#define RFCOMM_PIN_REQ      10 

#define RFCOMM_LISTENING    20
#define RFCOMM_CON_REQ      25 

#define RFCOMM_OBEX_IN      30
#define RFCOMM_OBEX_OUT     31

#define RFCOMM_STOP         100
#define RFCOMM_SHUTDOWN     200

pthread_mutex_t mutex_lib_state = PTHREAD_MUTEX_INITIALIZER;
byte lib_state = LIB_IDLE;

byte lib_threaded = 0;

byte rfcomm_connection_state = RFCOMM_IDLE;

int rfcomm_ttyfd;

//#define IO_BUF_SIZE 512 
//#define IO_BUF_SIZE 256 
//#define IO_BUF_SIZE 1024 
#define IO_BUF_SIZE 2048 

#include <libAPI.h>

/*-----------------------------------------------------------------------------------*/

//#define DEBUG_LOW 1
//#define DEBUG_MED 1
//#define DEBUG_HIGH 1

// Include core source from lwbt-0.1
#include "lwbt_memp.c"
#include "hci.c"
#include "l2cap.c"

#define LWBT_LAP 1

#include "sdp.c"
#include "rfcomm.c"
#include "fcs.c"

#define MEMP_SIZE          (LWIP_MEM_ALIGN_SIZE(200))

// Include core source (w/ modifications) from lwip
#include "uartif.c"
#include "pbuf.c"
// reduced version of memp.c from lwip
#include "memp_.c"

// reduced version of bt_ip_dt.c from lwbt-0.1/proj/dt 
#include "bt_rfcomm.c"

// functions for obex support
#include "obex.c"

// own version of hci handler for processing hci commands
// outside of the lwbt 'stack'
#include "hcilib2.c"

#include "netif/lwbt/bd_addr.h"

// Include fifo server from iSchmave (thanks!)
#include "fifo_server.c"

// Forward declarations
void *threaded_check_input(void *msg);
byte lib_status(void);

/*-----------------------------------------------------------------------------------*/
//  check_input() 
//
//  Check the fd for input at the lowest layer; if the loop count > 19
//  then the l2cap timer is triggered every 20 counts 
/*-----------------------------------------------------------------------------------*/
extern int check_input(int num_loops)  {

	int i;

	for (i=1; i<(num_loops+1); i++) { 
		phybusif_input(cb); /* clear out input */
		if (((double) i/20) == round((double) i/20)) {
//			l2cap_tmr();    
		}
		//sleep(1);
	}

	return 0;
}

/*-----------------------------------------------------------------------------------*/
//  threaded_check_input() 
//
//  Check the fd for input at the lowest layer; if the loop count > 19
//  then the l2cap timer is triggered every 20 counts.
//
//  This is used only internally and is not an API function
/*-----------------------------------------------------------------------------------*/
void *threaded_check_input(void *msg){

	int count;
	// Callbacks from this thread initiated from code in bt_rfcomm.c
	while( (lib_status() != LIB_STOP) ) {
		for (count=0; count<10; count++) {
			phybusif_input(cb);	
		}
	}

#ifdef DEBUG_HIGH
	printf("finishing threaded_check_input() ...\n");
	printf("   first with a bt_reset ...\n");
#endif
 	bt_rfcomm_start();	
#ifdef DEBUG_HIGH
	printf("   then some checking of phybusif input to clear out results of bt restart...\n");
#endif
	check_input(30);

#ifdef DEBUG_HIGH
	printf("   finally, stopping thread.  can re-start with either hci_monitor or hci_scan.\n");
#endif
        lib_state = LIB_IDLE;

	return 0;
}
/*-----------------------------------------------------------------------------------*/
//  lib_init(void)
//
//  Initialize everything required for the library
/*-----------------------------------------------------------------------------------*/
extern int lib_init(void) {

	printf("initializing library .... \n");
	if (lib_is_init > 0) {
		printf("  library already initialized.\n");
		return 0;             
	}
	lwbt_memp_init();
 
	// Check if this is a iphone or ipod-touch 
	if (getenv("DEVICE_IPOD") == NULL ) {
		// replacement for phybusif_init, taylored for the iPhone (see uartif.c) 
		printf("\nAssuming this is an iphone,\n  if not then set the environment variable DEVICE_IPOD=1.\n");
		phybusif_init_new_new();
	} else {
		printf("\nAssuming this is an ipod touch,\n  if not then double check the environment\n  variable DEVICE_IPOD.\n"); fflush(stdout);
		sleep(1);
		phybusif_init();
		sleep(1);
	}

	if(hci_init() != ERR_OK) {
		printf("HCI initialization failed!");
		exit(-1);
	}
	l2cap_init();
	sdp_init();
	rfcomm_init();

	// Allocate lib_callbacks structure and assign all callbacks to NULL 
	// and let user override this with lib_config
 	lib_callbacks = malloc(sizeof(struct lib_callbacks_struct));
	
	lib_callbacks->sdp_serve = NULL;
	lib_callbacks->pin_request = NULL;
	lib_callbacks->rfcomm_connect_request = NULL;
	lib_callbacks->thread_stopped = NULL;
	lib_callbacks->sp_connect_request = NULL;
	lib_callbacks->sp_closed = NULL;
	lib_callbacks->obex_transfer_request = NULL;
	lib_callbacks->obex_start = NULL;
	lib_callbacks->obex_packet_receive = NULL; 
	lib_callbacks->obex_done = NULL;
	lib_callbacks->device_found = NULL;
	lib_callbacks->scan_complete = NULL;

	printf("lwBT library initialized.\n\n");

	lib_is_init = 1;

	return lib_state;
}

/*-----------------------------------------------------------------------------------*/
//  lib_shutdown(void)
//
//  Do another reset of the chip then close down the fd so it has to be re-initiazed 
//  again before use
/*-----------------------------------------------------------------------------------*/
extern int lib_shutdown(void) {

#ifdef DEBUG_HIGH
	printf("shutting down liblwbt...\n");
#endif
	bt_rfcomm_start();
	uninitialise(fd);
	
#ifdef DEBUG_HIGH
	printf("   hci device unitialized.  liblwbt is complete.\n");
#endif
	return lib_state;
}
/*-----------------------------------------------------------------------------------*/
//  lib_status(void)
//
//  Get the status of the library for internal processing only (not a part of the,
//  API, use 'get_lib_status()' below for API access)
/*-----------------------------------------------------------------------------------*/
byte lib_status(void) {
	byte local_lib_state;

	pthread_mutex_lock(&mutex_lib_state);
        local_lib_state = lib_state;
	pthread_mutex_unlock(&mutex_lib_state);

	return local_lib_state; 
}
/*-----------------------------------------------------------------------------------*/
//  get_lib_status(void)
//
//  Get the status of the library
/*-----------------------------------------------------------------------------------*/
extern int get_lib_status(void) {
	byte local_lib_state;

	pthread_mutex_lock(&mutex_lib_state);
        local_lib_state = lib_state;
	pthread_mutex_unlock(&mutex_lib_state);

	return (int) local_lib_state; 
}
/*-----------------------------------------------------------------------------------*/
//  lib_stop(void)
//
//  Force a stop of any polling loop processing that were started as separate threads 
//  and detached.
/*-----------------------------------------------------------------------------------*/
extern int lib_stop(void) {

	pthread_mutex_lock(&mutex_lib_state);
	lib_state = LIB_STOP;
	pthread_mutex_unlock(&mutex_lib_state);

	return 0; 
}
/*-----------------------------------------------------------------------------------*/
//  lib_setup(void)
//
//  Setup the library, including resetting memory buffers and getting 
//  the local mac addr and name
/*-----------------------------------------------------------------------------------*/
extern int lib_setup(void) {

	static const u8_t real_sp[] = {
		0x35, 0x8,			/* Service record handle attribute */
		0x9, 0x0, 0x0, 0xa, 0x0, 0x0, 0xff, 0xff,
               
		0x35, 0x8, 			/* Service class ID list attribute (for SP)*/
		0x9, 0x0, 0x1, 0x35, 0x3, 0x19, 0x11, 0x1,
               
		0x35, 0x11,			/* Protocol descriptor list attribute */
		0x9, 0x0, 0x4,      0x35, 0x0c, /*csum*/ 0x35,    0x03, 0x19, 0x01, 0x00,   0x35, 0x5, 0x19, 0x0, 0x3,/*rfcomm*/  0x08, 0x01, /*channel 1*/
       
		0x35, 0x08, 			/*pub brsw group -- root*/
		0x09, 0x00, 0x05, 0x35, 0x03, 0x19, 0x10, 0x02,
       
		0x35, 0x0d, 			/* Profile Descriptor List */
		0x09, 0x00, 0x09, 0x35, 0x08, 0x35, 0x06, 0x19, 0x11, 0x01, 0x09, 0x01, 0x00,
       
		0x35, 0x10,
		0x09, 0x01, 0x00, 0x25, 0x0b, 0x53, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x20, 0x50, 0x6f, 0x72, 0x74, 0x00
               /* Srv Name -- "Serial port" im assuming its unicode...*/

	};

	static const u8_t real_obex [] = {
		0x35, 0x8,
		0x9, 0x0, 0x0, 0xa, 0x0, 0x01, 0x00, 0x00, /* Service record handle attribute rechndl used to be 0x00, 0xff, 0xff */
		0x35, 0x8,
		0x9, 0x0, 0x1, 0x35, 0x3, 0x19, 0x11, 0x05, /* Service class ID list attribute (for OBEX)*/
               
		0x35, 0x16,
		0x9, 0x0, 0x4,      0x35, 0x11, 0x35,    0x03, 0x19, 0x01, 0x00,   0x35, 0x5, 0x19, 0x0, 0x3,/*rfcomm*/  0x08, 0x01, /*channel 1*/
               /* Protocol descriptor list attribute */    0x35, 0x03, 0x19, 0x00, 0x08, //addition obex part

		0x35, 0x08,
		0x09, 0x00, 0x05, 0x35, 0x03, 0x19, 0x10, 0x02, /*pub brsw group -- root*/
       
		0x35, 0x0d,
		0x09, 0x00, 0x09, 0x35, 0x08, 0x35, 0x06, 0x19, 0x11, 0x05, 0x09, 0x01, 0x00, /* Profile Descriptor List */
       
		0x35, 0x15,
		0x09, 0x01, 0x00, 0x25, 0x10, 0x4F, 0x62, 0x6A, 0x65, 0x63, 0x74, 0x20, 0x45, 0x78, 0x63, 0x68, 0x61, 0x6E, 0x67, 0x65, 0x00,
               /* Srv Name -- "Object Exchange" im assuming its unicode...? */

		0x35, 0x13,
		0x09, 0x03, 0x03, 0x35, 0x0E, 0x08, 0x01, 0x08, 0x02, 0x08, 0x03, 0x08, 0x04, 0x08, 0x05, 0x08, 0x06, 0x08, 0xFF /*SuppFormatsList */
	};


	printf("setting up library ....\n");
	if (lib_is_setup > 0) {
		printf("  library already setup.\n");
		return 0;             
	}
#ifdef DEBUG_HIGH
	printf("   resetting physical buffer ...\n"); fflush(stdout);
#endif
	cb = malloc(sizeof(struct phybusif_cb));
	phybusif_reset(cb);

#ifdef DEBUG_HIGH
	printf("   starting bluetooth ...\n"); fflush(stdout);
#endif

	bt_rfcomm_start();


#ifdef DEBUG_HIGH
	printf("   clearing out physical input buffers (repeated checking of input) \n");
#endif
	check_input(10);

	u8_t class_of_device[10] = {0x0c,0x02,0x70};
	hci_write_cod(class_of_device);

	check_input(10);

	struct sdp_record *record;
	if((record = sdp_record_new((u8_t *)real_sp, sizeof(real_sp))) == NULL) {
		LWIP_DEBUGF(BT_IP_DEBUG, ("lib_setup: Could not alloc SDP record\n"));
		printf("lib_setup: Could not alloc SDP record\n");
		//return ERR_MEM;
	} else {
		sdp_register_service(record);
	}

	struct sdp_record *record2;
	if((record2 = sdp_record_new((u8_t *)real_obex, sizeof(real_obex))) == NULL) {
		LWIP_DEBUGF(BT_IP_DEBUG, ("lib_setup: Could not alloc SDP record\n"));
		printf("lib_setup: Could not alloc SDP record\n");
		//return ERR_MEM;
	} else {
		sdp_register_service(record2);
	}


	printf("lwBT library ready for operation.\n\n");

	lib_is_setup = 1;

	return 0;
}

/*-----------------------------------------------------------------------------------*/
//  set_local_name(byte **string ) 
//
//  Use hci commands to set the local name 
/*-----------------------------------------------------------------------------------*/
extern int set_local_name(char **local_name, int name_length) {
#ifdef DEBUG_MED
	printf("setting local name ...\n");
#endif
        byte data[248];
	memset(data, 0, 248);

  	int count, i;
	byte temp;
       
        for (i=0; i<name_length; i++) {
		temp = (local_name[0])[i];
 		//if (temp != NULL) {
 		if (temp != 0 ) {
			data[i] = temp;
 		} else {
			i = 248;
		}
	}

	count = hci_command_handler(HCI_CMD_WRT_LOC_NAME, data);

	u8_t class_of_device[10] = {0x0c,0x02,0x70};
	hci_write_cod(class_of_device);

	check_input(10);

	return 0;
}

/*-----------------------------------------------------------------------------------*/
//  get_device_name(byte value) 
//
//  Use hci commands to get friendly name from other bluetooth device.
/*-----------------------------------------------------------------------------------*/
byte returned_device_name_data[256];
extern int get_device_name(byte *bt_mac_addr, char **device_name) {

  	int count;

	memset(returned_device_name_data,0,256);

	for (count = 0; count<6; count++) {
		returned_device_name_data[5-count] = bt_mac_addr[count];
	}
     	returned_device_name_data[6] = 0x02;
     	returned_device_name_data[7] = 0x00;
     	returned_device_name_data[8] = 0x00;
     	returned_device_name_data[9] = 0x00;
	
	count = hci_command_handler(HCI_CMD_RD_DEV_NAME, returned_device_name_data);

  	device_name[0] = (char *) returned_device_name_data;

	return 0;
}
/*-----------------------------------------------------------------------------------*/
//  set_scan_enable(byte value) 
//
//  Use hci commands to set scan enable 
/*-----------------------------------------------------------------------------------*/
extern int set_scan_enable(byte value) {
	int i;

#ifdef DEBUG_MED
	printf("setting scan enable ...\n");
#endif
        hci_write_scan_enable(value);

        for (i=0;i<10; i++) {
        	phybusif_input(cb); /* clear out input */
	}

	return 0;
}

/*-----------------------------------------------------------------------------------*/
//  get_local_name(byte *return_string ) 
//
//  Use hci commands to get the local name 
/*-----------------------------------------------------------------------------------*/
extern int get_local_name(char **local_name) {
#ifdef DEBUG_MED
	printf("getting local name ...\n");
#endif
        byte returned_data[200];
  	int count;
	count = hci_command_handler(HCI_CMD_RD_LOC_NAME, returned_data);

	local_name[0] = (char *) returned_data;

	return 0;
}

/*-----------------------------------------------------------------------------------*/
//  get_local_mac_addr(byte *return_string ) 
//
//  Use hci commands to get the local mac address
/*-----------------------------------------------------------------------------------*/
extern int get_local_mac_addr(char **bt_mac_addr) {
#ifdef DEBUG_MED
	printf("getting local mac addr...\n");
#endif
        byte returned_data[18];
  	int count;
	count = hci_command_handler(HCI_CMD_RD_BD_ADDR, returned_data);

	//returned_data[17] = NULL;
	returned_data[17] = 0;
	bt_mac_addr[0] = (char *) returned_data;

	return 0;
}

/*-----------------------------------------------------------------------------------*/
//  connect_dev_io() 
//
//  Sets up the fd for external i/o from/to the (assumed connected) rfcomm channel 
/*-----------------------------------------------------------------------------------*/
extern int connect_dev_io(void) {
#ifdef DEBUG_MED
	printf("setting up ttyfd for rfcomm i/o ... \n");
#endif

	// Setup the tty for the fifo server
	fifo_server_setup();

	// Go into fifo loop (check for input from either fifo_fd or tty fd used by lwbt for HCI comm)
	fifo_server_loop();
	
	return 0;
}

/*-----------------------------------------------------------------------------------*/
//  rfcomm_output() 
//
//  send data out the created rfcomm connection  
/*-----------------------------------------------------------------------------------*/
extern int rfcomm_output(byte *data, int num_bytes) {
#ifdef DEBUG_MED
	printf("sending data out the rfcomm connection...\n");
#endif

	our_rfcomm_output(data, num_bytes);

	int i;
	for (i=0; i< 10; i++) {	
		printf("  waiting for input after sending rfcomm...\n");
		check_input(10);
	}
	
	return 0;
}

/*-----------------------------------------------------------------------------------*/
//  connect_pin_req() 
//
//  Respond to pin request to continue rfcomm connection  
/*-----------------------------------------------------------------------------------*/
extern int connect_pin_req(char *pin, byte pinlen) {
#ifdef DEBUG_MED
	printf("responding to pin request with: %s (length = %d) \n", pin, pinlen);
#endif

	pin_reply((u8_t *) pin, (u8_t) pinlen);

	int count = 0;
	int max_count = 35;
	lib_is_connecting = 1;
	rfcomm_connection_state = RFCOMM_IN_PROGRESS;
	while ((count < max_count) & (lib_is_connecting > 0) ) {
		check_input(10);
		count ++;
	}

#ifdef DEBUG_MED
	if (lib_is_connecting == 0) {printf("   connection flag cleared. connection status = %d \n", rfcomm_connection_state);}
#endif
	if (lib_is_connecting == 1) {printf("   timeout error, should not have reached this.....\n");}
	
	return rfcomm_connection_state;
}

// TODO: hci_monitor returns if a rfcomm connection is requested
// TODO: write accept_rfcomm lib function for calling app to respond to incoming connection request (rfcomm, l2cap and hci) 
// TODO: write accept_pin_req lib function to respond interactively to pin request on incoming rfcomm connection
// TODO: write accept_dev_io lib function to proceed with SP support of incoming rfcomm connection
// TODO: write accept_obex lib function to accept obex connection after rfcomm connection accepted

// TODO: allow profile support configuration when starting hci_monitor (what sdp records to serve)

/*-----------------------------------------------------------------------------------*/
//  hci_monitor() 
//
//  start engough to run sdp server and listen for rfcomm connections
/*-----------------------------------------------------------------------------------*/
extern int hci_monitor(byte threaded_mode) {
#ifdef DEBUG_MED
	printf("setting up and running sdp server...\n");
#endif

	struct l2cap_pcb *l2cappcb;
	struct rfcomm_pcb *rfcommpcb;

	if((l2cappcb = l2cap_new()) == NULL) {
		printf(" -----> Could not alloc L2CAP pcb\n");
		return -1;
	} 

	// if l2cap connection request is made....      	
	l2cap_connect_ind(l2cappcb, SDP_PSM, our_l2ca_connect_ind);

	if((l2cappcb = l2cap_new()) == NULL) {
		printf(" -----> Could not alloc second L2CAP pcb\n");
		return -1;
	} 
	l2cap_connect_ind(l2cappcb, RFCOMM_PSM, our_l2ca_connect_ind);

	if((rfcommpcb = rfcomm_new(NULL)) == NULL) {
		LWIP_DEBUGF(BT_IP_DEBUG, ("lap_init: Could not alloc RFCOMM PCB for channel 0\n"));
		return ERR_MEM;
	}
	rfcomm_listen(rfcommpcb, 0, rfcomm_accept);

	LWIP_DEBUGF(RFCOMM_DEBUG, ("lap_init: Allocate RFCOMM PCB for CN 1******************************\n"));
	if((rfcommpcb = rfcomm_new(NULL)) == NULL) {
		LWIP_DEBUGF(BT_IP_DEBUG, ("lap_init: Could not alloc RFCOMM PCB for channel 1\n"));
		return ERR_MEM;
	}
	rfcomm_listen(rfcommpcb, 1, rfcomm_accept);

	rfcomm_recv(rfcommpcb, obex_rfcomm_input);

	global_pcb = rfcommpcb;

	int return_val = 0;
	int count = 0;

	lib_threaded = threaded_mode;

	rfcomm_connection_state = RFCOMM_LISTEN;

	pthread_t phybus_monitor_thread;
	int monitor_thread_handle;
	byte message[100];

	if (lib_threaded == 1) {
		// Start phybusif monitor with non-NULL callbacks enabled
#ifdef DEBUG_HIGH
		printf("starting separate thread to monitor uart ...");
#endif
		monitor_thread_handle = pthread_create(&phybus_monitor_thread, NULL, threaded_check_input, (void *) message);
#ifdef DEBUG_HIGH
		printf("   thread started. \n");
#endif
		
	} else {
		// Process until next state achieved 
		while ((lib_status() != LIB_STOP) & (rfcomm_connection_state != RFCOMM_CON_REQ)) {
			count = 0;
			while ((count<10) & (rfcomm_connection_state != RFCOMM_CON_REQ)) {
				phybusif_input(cb); /* Check for input */
				count++;
			}
				
		}
		return_val = rfcomm_connection_state;
	}

	return return_val;
}

// TODO: write obex_push lib function to push files (after rfcomm connection established)
//
/*-----------------------------------------------------------------------------------*/
//  connect_rfcomm() 
//
//  Use hci commands to get the local mac address
/*-----------------------------------------------------------------------------------*/
extern int connect_rfcomm(byte *bt_mac_addr, byte interactive_pin) {
#ifdef DEBUG_MED
	printf("attempting rfcomm connection...\n");
#endif

	struct bd_addr bdaddr;
	int i;
	struct l2cap_pcb *l2cappcb;

	// Copy bt address over in reverse order
	for (i=0; i<6; i++) {
		bdaddr.addr[5-i] = bt_mac_addr[i];
	}	

	if((l2cappcb = l2cap_new()) == NULL) {
		printf(" -----> Could not alloc L2CAP pcb\n");
		return -1;
	} 

      	lib_interactive_pin = interactive_pin;

	// if l2cap connection request is made....      	
	//l2cap_connect_ind(l2cappcb, SDP_PSM, our_l2ca_connect_ind);

	// Start the rfcomm connection by first makeing a l2cap connection
	// and retreiving pertinant sdp service records; if a viable record
	// is found and w/ an appropriate (non-zero?) channel then the connection is made
        //l2ca_connect_req(l2cappcb, &(bdaddr), RFCOMM_PSM, 1, l2cap_connected);
        l2ca_connect_req(l2cappcb, &(bdaddr), SDP_PSM, 0, l2cap_connected);

	int count = 0;
	int max_count = 350;
	lib_is_connecting = 1;
	rfcomm_connection_state = RFCOMM_IN_PROGRESS;
	while ((count < max_count) & (lib_is_connecting > 0) ) {
		check_input(1);
		count ++;

	}

#ifdef DEBUG_MED
	if (lib_is_connecting == 0) {printf("   connection flag cleared. connection status = %d \n", rfcomm_connection_state);}
#endif
	if (lib_is_connecting == 1) {printf("   timeout error, should not have reached this.....\n");}

	return rfcomm_connection_state;
}

/*-----------------------------------------------------------------------------------*/
//  hci_scan(byte *return_string, byte scan_time, threaded ) 
//
//  Library interface to hci_inquiry2(); returns # of devices found and within scan_time (seconds)
//  single string (uchar array) containing scan information with a single space ' ' header
//  for each device found; for example:
//   00:01:02:03:04:05 10:11:12:13:14:15 .....
/*-----------------------------------------------------------------------------------*/
extern int hci_scan(char **return_string, byte scan_time, byte threaded_mode) {


        int max_devices = 0;

        int count;

	sprintf((char *) hci_scan_result, "None");
        hci_scan_result[100] = 0;
    
        hci_scan_num_devices = 0;

#ifdef DEBUG_MED
	printf("   inquiring on other devices (scan_time = %d)...\n", scan_time); fflush(stdout);
#endif
 	lib_is_scanning = 1;

	lib_threaded = threaded_mode;

	// If function called in threaded mode then the user-side keeps track
	// of the device info, and the # of devices, as hci scan results are received.
	// In non-threaded mode the data is stored in the internal and finite sized 
	// hci_scan_result so the max # of devices must be specified.
	if (lib_threaded == 1) {
#ifdef DEBUG_LOW
		printf("    no limit on # of devies to scan for ...\n");
#endif
		hci_inquiry2(0x009E8B33, scan_time, 0, inquiry_complete);
	} else {
#ifdef DEBUG_LOW
		printf("    will scan for up to %d devices ...\n", max_devices);
#endif
printf("got here...\n");
		hci_inquiry2(0x009E8B33, scan_time, max_devices, inquiry_complete);
	}

	pthread_t phybus_monitor_thread;
	int monitor_thread_handle;
	byte message[100];


	if (lib_threaded == 1) {
		// Start phybusif monitor with non-NULL callbacks enabled
#ifdef DEBUG_HIGH
		printf("starting separate thread to monitor uart for hci_scan ...");
#endif
		monitor_thread_handle = pthread_create(&phybus_monitor_thread, NULL, threaded_check_input, (void *) message);
#ifdef DEBUG_HIGH
		printf("   thread started. \n");
#endif

		// Okay, now we can immediately return control to the main function
		return 0;

	}
printf("got here...\n");
	count = 0;
	while (count < (20*scan_time)) {
		phybusif_input(cb); // Check for input 
		count = count + 1;
		// check scanning flag to wait until complete
		if (lib_is_scanning == 0) {
#ifdef DEBUG_MED
			printf("    scanning flag cleared by inquiry complete. \n");
#endif
			count = 20*scan_time;		
		}
	}
#ifdef DEBUG_MED
	printf("scan finished.\n");
#endif

	//memcpy(return_string[0], hci_scan_result, 200);
	return_string[0] = (char *) hci_scan_result;

	return hci_scan_num_devices;
}





